<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ES5-借用构造函数属性继承</title>
  <!-- 
  在 JavaScript ES5 中，借用构造函数是一种常见的属性继承方式，它允许子类通过调用父类的构造函数来继承父类的属性。这种方式的主要优点是可以在子类中初始化父类的属性。
  1. 借用构造函数的基本概念
  - 借用构造函数是指在子类的构造函数中调用父类的构造函数，以便子类实例能够访问父类的属性。
  - 这种方式通常在子类构造函数的开头使用  `call()`  或  `apply()`  方法来调用父类构造函数。

  2. 实现步骤
  以下是使用借用构造函数实现属性继承的基本步骤：

   2.1 定义父类构造函数
  首先定义一个父类构造函数，并在其中初始化属性。
  function Parent(name) {
      this.name = name;
      this.parentProperty = "I am a parent property";
  }
   2.2 定义子类构造函数
  然后定义一个子类构造函数，并在其中调用父类构造函数。
  function Child(name, age) {
      Parent.call(this, name); // 借用构造函数
      this.age = age; // 子类特有的属性
  }
   2.3 创建实例
  最后，通过子类构造函数创建实例。
  var childInstance = new Child("Alice", 10);
  console.log(childInstance.name); // 输出: Alice
  console.log(childInstance.age); // 输出: 10
  console.log(childInstance.parentProperty); // 输出: I am a parent property
  3. 优缺点
  - 优点：
    - 可以在子类构造函数中传递参数，初始化父类的属性。
    - 每个实例都有自己独立的父类属性，避免了共享属性导致的潜在问题。

  - 缺点：
    - 方法不能共享：每个实例都会重新创建父类的方法，导致内存浪费。
    - 如果父类有很多方法，可能会造成性能问题。

  4. 结合原型链
  为了避免方法的重复创建，通常会结合原型链继承一起使用。可以在子类的原型上设置父类的原型，以实现方法的共享。
  Child.prototype = Object.create(Parent.prototype);
  Child.prototype.constructor = Child;

  // 添加子类特有的方法
  Child.prototype.sayAge = function() {
      console.log("I am " + this.age + " years old.");
  };

  var childInstance = new Child("Alice", 10);
  childInstance.sayAge(); // 输出: I am 10 years old.
  5. 总结
  借用构造函数是一种简单有效的属性继承方式，特别适合需要在子类中初始化父类属性的场景。通过结合原型链，可以实现方法的共享，从而提高内存使用效率。理解借用构造函数的实现机制对于构建复杂的对象模型和编写高效的 JavaScript 代码非常重要。
  -->
</head>
<body>

  <script>
    // 定义Person构造函数(类)，添加属性和方法
    function Person(name, age, height, address) {
      this.name = name
      this.age = age
      this.height = height
      this.address = address
    }

    Person.prototype.running = function() {
      console.log("running~")
    }
    Person.prototype.eating = function() {
      console.log("eating~")
    }

    // 定义学士类
    function Student(name, age, height, address, school, sno) {
      // 借用构造函数继承属性
      Person.call(this, name, age, height, address)
      this.school = school
      this.sno = sno
    }

    // 原型链继承方法
    // Student.prototype = Object.create(Person.prototype)
    // Student.prototype.constructor = Student
   
    var p = new Person("borrow", 18)
    Student.prototype = p

    // 添加子类特有的方法
    Student.prototype.studying = function() {
      console.log("studying~")
    }

    // 创建学生
    var stu1 = new Student("kobe", 30, 111, 100)
    var stu2 = new Student("james", 25, 111, 100)
    stu1.running()
    stu1.studying()

    console.log(stu1.name, stu1.age)
    console.log(stu1)
    console.log(stu2.name, stu2.age)
    
  </script>
  
</body>
</html>